[Android][Framework] PlayAutoInstall配置流程总结


我这里有谷歌给OEM提供的官方文档,需要的可以联系

什么是PAI

PAI (PlayAutoInstall) 是一个自动下载安装APK到手机,并且摆放在Launcher对应位置的一个机制。

因为国内没有GMS,所以很多人没接触过这个机制。这个机制其实对于运营商定制来说非常重要,比如美国的运营商,一个运营商有很多地区很多种类的SIM卡,当插上不同地区的SIM卡,运营商定制的手机就会下载不同的APP摆放在界面不同的位置。

这么说有些抽象,看下面示例图:

首先是出厂刚开机Launcher的界面:

当手机插上SIM卡联网,PlayStore会通过PAI机制下载安装摆放不同的APP:

界面一下子就变丰富了。

PAI 流程

本地编译一个PlayAutoInstallConfig.apk,签名上传到APFE服务器,APFE会验证配置信息,并提供给PlayStore。当目标设备第一次开机启动并且联网(现在不必要登录谷歌帐号),这些应用就会加入下载队列,自动下载到手机。

配置菜单

先聊一下APFE会验证的配置信息。

需要的配置信息包括:

  • 指纹(必须)
  • 城市(可选)
  • 运营商(可选)
  • 需要下载的App列表
  • 应用在桌面的位置信息

后两项是编译在PlayAutoInstallConfig.apk中的,前三项是把apk上传到服务器时需要填写的。

上传服务器配置页面如下:

配置信息的前三项匹配项如果填写,就必须要完全匹配才能应用到手机。我遇到一个问题是配置上传后PlayAutoInstallConfig.apk会在SetupWizard过程中下载到手机,但需要PlayStore下载的应用怎么都不下载。后来发现是在上传apk到服务器时运营商填的不对,导致无法下载。因为尝试填写几种运营商Name都不能正常工作,最后解决方案是只匹配指纹,不匹配城市和运营商(减少过滤项),这样手机就可以和PlayStore信息匹配,然后就可以自动下载了。

关于其余配置,参考下面表格:

Config APK

对上表中出现一个Config APK 做一些解释。

手机内必须要先预置一个符合下列条件的stub APK:

  • 为一个系列的设备设置唯一的包名,包名格式为android.autoinstalls.config..
  • 必须配置一个receiver ”android.autoinstalls.config.action.PLAY_AUTO_INSTALL”,并且设置exported为flase
  • 在预置的App里只能有一个定义这个receiver
  • versionCode必须定义成1
  • APK必须预置在/system/app (不能定义成privileged,即不能放/priv-app)
  • 必须用私有Key签名
  • 不能定义permissions/activities/其他receivers/content provider/services

这个APK其实就一个Manifest,没有特别的内容。




    

        
            
                
            
              
    

相关的MakeFile如下

include $(CLEAR_VARS)
apk_variant := stub
APK_VERSION := 1
include $(BUILD_APK)

PlayAutoInstallConfig.apk

这个APK是我们真正配置的APK。

它和前面的APK的关系是:包名一致。因为PAI机制需要本地存在一个这个包名的APK,在开机的SetupWizard阶段,(如果联网)它会从服务器下载这个写有对应配置的APK到手机上,替换掉那个Stub APK。

关于PAIconfig APK的配置:

  • 上传的APK(也就是我们编出来的APK)包名与指纹要和stub一致
  • APK签名要一致
  • 和stub配置同样的receiver
  • versionCode必须大于1000
  • APK必须包含launcher布局配置的xml文件(即后面会提到的default_layout),不然上传会失败,因为上传前会检查这个xml文件,然后会把要下载的app显示出来。所以也必须要求至少定义一个需要下载的app。最多50个,建议放10~15个。(文档还要求autoinstall的应用必须在launcher上指定摆放位置,目前看来是不需要的,有可能bb launcher做了修改)
  • 界面会有文件夹,文件夹名称string在APK本地resource定义,支持国际化。
  • 需要自动下载的APK对设备来讲必须是在PlayStore发布的,并且对该地区用户可见
  • 不能定义permissions/activities/其他receivers/content provider/services

在这个APK里就要写需要下载的APK信息了,基本格式如下:

参数screen是第几屏,x,y是在屏幕的位置,从0开始。

    autoinstall开头是需要PlayStore下载的,
    

    appwidget开头是桌面控件。span属性设定控件的宽高
    

    appicon就是纯粹摆放APP的位置
    

    folder是文件夹,里面可以放多个app
    
        
    

    action是shortcut快捷键,key是LAUNCHER里面定义的
    

    
    (按顺序?或者按照rank属性决定)最后四个是DOCKER的app icon
    
    
    
    

代码结构

在res-PAI目录中,xml有两个,default_layout中要填写的应用(需要从PlayStore自动下载的应用),然后再oem_layout填写该应用的位置。如果其他途径也会下载应用,只需要把应用信息写在oem_layout即可。

验证流程

烧一个新手机,启动进SetupWizard,在过程中联网,登录谷歌帐号(现在这一步不必要了)。在设置好谷歌帐号之后,就会自动下载PAI apk到手机,替换默认的stub生效。等到进入Launcher界面,Launcher就会加载这个apk,把icon配置到对应位置上。与此同时,PlayStore会下载配置的App。

从工作流程看,如果想调试界面,就可以不reset手机,直接把编译好的APK替换默认的stub。这时候因为launcher已经启动过,所以不会主动加载配置的apk,需要从settings清空launcher数据,强制加载,就可以看到修改的界面了。

更多

Launcher里面有AutoInstallsLayout.java ,可以阅读了解。

从上面配置可以看出,写配置需要了解应用的包名,主Activity的类名,所以需要用到am和pm命令去查找,所以写了一个脚本方便获取APK的信息。

#!/bin/bash
help_info(){
    echo "-a get current activity"
    echo "-p list packages in device, can add a package name"
    echo "-m dump apk's AndroidManifest, need add a APK"
}

if [ $# -eq 0 ]
then
    help_info
else
    echo "arg count is $#"
fi

case "$1" in
    -a)
    adb shell dumpsys activity activities
    ;;
    -p)
    if [ $# -eq 2 ]
    then
        adb shell pm list packages -f "$2"
    elif [ $# -eq 1 ]
    then
        adb shell pm list packages
    else
    echo "check the arguement"
    fi
    ;;
    -m)
    if [ $# -eq 2 ]
    then
    aapt dump xmltree "$2" AndroidManifest.xml
    else
    echo "need file path"
    fi
esac

文章作者: Wossoneri
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 Wossoneri !
评论
  目录